package com.service.component.shiro;

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SessionsSecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;


@Configuration
/**
 * @author ：Calvin
 * @date ：Created in 2021/7/16 14:35
 * @description：ShiroConfig
 * @modified By：
 * @version: 1.0.0$
 */
public class ShiroConfig {
  /**
   * Session Manager：会话管理
   * 即用户登录后就是一次会话，在没有退出之前，它的所有信息都在会话中；
   * 会话可以是普通JavaSE环境的，也可以是如Web环境的；
   */
  @Bean
  public SessionManager sessionManager(){
    DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
    //设置session过期时间
    sessionManager.setGlobalSessionTimeout(60 * 60 * 1000);
    sessionManager.setSessionValidationSchedulerEnabled(true);
    // 去掉shiro登录时url里的JSESSIONID
    sessionManager.setSessionIdUrlRewritingEnabled(false);
    return sessionManager;
  }

  /**
   * SecurityManager：安全管理器
   */
  @Bean
  public SessionsSecurityManager securityManager(SessionManager sessionManager) {
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    securityManager.setSessionManager(sessionManager);
    securityManager.setRealm(getCustomRealm());
    return securityManager;
  }
  /**
   * ShiroFilter是整个Shiro的入口点，用于拦截需要安全控制的请求进行处理
   */
  @Bean
  public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
    ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
    shiroFilter.setSecurityManager(securityManager);
    shiroFilter.setLoginUrl("/login");
    shiroFilter.setUnauthorizedUrl("/notRole");
    Map<String, String> filterMap = new LinkedHashMap<>();
    /*authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问*/
    /*swagger*/
    filterMap.put("/api/**", "anon");
    /*系统*/
    filterMap.put("/user/login", "anon");
    filterMap.put("/user/register", "anon");
    filterMap.put("/**", "authc");
    shiroFilter.setFilterChainDefinitionMap(filterMap);
    return shiroFilter;
  }
  /**
   * 管理Shiro中一些bean的生命周期
   */
  @Bean
  public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
    return new LifecycleBeanPostProcessor();
  }
  /**
   * 扫描上下文，寻找所有的Advistor(通知器）
   * 将这些Advisor应用到所有符合切入点的Bean中。
   */
  @Bean
  public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
    DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
    proxyCreator.setProxyTargetClass(true);
    return proxyCreator;
  }
  /**
   * 匹配所有加了 Shiro 认证注解的方法
   */
  @Bean
  public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
    AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
    advisor.setSecurityManager(securityManager);
    return advisor;
  }

  @Bean
  public CustomRealm getCustomRealm(){
    CustomRealm customRealm = new CustomRealm();
    //使用HashedCredentialsMatcher带加密的匹配器来替换原先明文密码匹配器
    HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
    //指定加密算法
    hashedCredentialsMatcher.setHashAlgorithmName("MD5");
    //设置散列次数
    hashedCredentialsMatcher.setHashIterations(1024);
    customRealm.setCredentialsMatcher(hashedCredentialsMatcher);
    return customRealm;
  }
}

